﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using Generator.Helpers;
using System.Collections.ObjectModel;
using System.Xml;

namespace Generator.Service
{
    /// <summary>
    /// Cette classe représente le générateur de VSTemplate
    /// </summary>
    public class VSSolutionTemplateGenerator : VSTemplateGenerator
    {
        private int projectCounter;
        private int iterration;

        private XDocument referencePathsDocument;

        private Collection<VSProjectTemplateGenerator> vsProjectTemplateGeneratorCollection;

        #region Constructor

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        public VSSolutionTemplateGenerator()
            : base()
        {
            this.vsProjectTemplateGeneratorCollection = new Collection<VSProjectTemplateGenerator>();
            this.referencePathsDocument = new XDocument();
            this.referencePathsDocument.Add(new XElement("References"));
        }

        #endregion

        #region Abstract Execute Method

        /// <summary>
        /// Cette méthode permet de générer le template VS dans le répertoire Output
        /// </summary>
        /// <param name="sourceFolder">Répertoire Source pour créer le VSTemplate</param>
        /// <param name="outputFolder">sorite du fichier</param>
        public override void Execute(string sourceFolder, string outputFolder)
        {
            this.projectCounter = 0;
            this.SourceFolder = sourceFolder;
            this.OutputFolder = outputFolder;
            this.Content = this.vsTemplateHelper.ReadDocument(".\\Assets\\" + VSTemplateHelper.SOLUTION_TEMPLATE_NAME);

            this.Parse(this.Content.Root.Element(VSTemplateHelper.TEMPLATE_CONTENT).Element(VSTemplateHelper.NAMESPACE + "ProjectCollection"), this.SourceFolder, this.OutputFolder);

            this.ParseReferences();

            this.ParseWebSiteReference();

            this.referencePathsDocument.Save(this.OutputFolder + "SolutionFolder.xml");

            var resultContent = this.textReplaceHelper.ContenctReplaceParse(this.Content);
            resultContent.Save(this.OutputFolder + VSTemplateHelper.SOLUTION_TEMPLATE_NAME);

            File.Copy(".\\Assets\\__PreviewImage.jpg", this.OutputFolder + "__PreviewImage.jpg", true);
            File.Copy(".\\Assets\\__TemplateIcon.jpg", this.OutputFolder + "__TemplateIcon.jpg", true);
        }

        #endregion

        private void Parse(XElement element, string sourceFolder, string outputFolder)
        {
            var currentElement = element;

            // Note : Si l'on souhaite ajouter le répertoire de solution "Solution Items", code ci-dessous
            //if (outputFolder.Equals(this.OutputFolder))
            //{
            //    currentElement = this.vsTemplateHelper.CreateSolutionFolderElement("Solution Items");
            //    element.Add(currentElement);
            //}

            // Parcours des fichiers
            var fileCollection = Directory.GetFiles(sourceFolder);
            foreach (var item in fileCollection)
            {
                var shortfilename = this.fileHelper.ShortFilename(item);

                // Copie du fichier dans le répertoire cible
                if (this.fileHelper.CheckFilename(shortfilename))
                {
                    var outputFilename = outputFolder + shortfilename;

                    File.Copy(item, outputFilename, true);

                    // Ajout dans le fichier de l'element
                    currentElement.Add(this.vsTemplateHelper.CreateProjectItemElement(shortfilename, item.Replace(this.SourceFolder, "")));
                }
                else
                {
                    // Nothing
                }
            }
            // Repositionne le bon folder.
            currentElement = element;

            // Parcours des répertoires
            var folderCollection = Directory.GetDirectories(sourceFolder);
            foreach (var item in folderCollection)
            {
                var shortFolder = this.fileHelper.ShortFolder(item);
                iterration++;
                var reducedShortFolder = shortFolder.First() + iterration.ToString();
                if (this.fileHelper.CheckFolder(shortFolder))
                {
                    // Traitement sur le repertoire contenant un projet
                    string projectFilename = string.Empty;
                    if (this.fileHelper.CheckContainProjectFile(item, out projectFilename))
                    {
                        // Créer le répertoire Output
                        Directory.CreateDirectory(outputFolder + reducedShortFolder);

                        // Créer l'element XML dans le VsTYemplate
                        var shortprojectFilename = this.fileHelper.ShortFilename(projectFilename);
                        var newElement = this.vsTemplateHelper.CreateProjectTemplateLinkElement(shortprojectFilename, outputFolder.Replace(this.OutputFolder, "") + reducedShortFolder);
                        currentElement.Add(newElement);

                        // Traitement du VSTemplate de project
                        this.projectCounter++;
                        var projectGenerator = new VSProjectTemplateGenerator();
                        projectGenerator.ProjectFilename = projectFilename;
                        projectGenerator.ProjectId = this.projectCounter;
                        projectGenerator.Execute(item, outputFolder + reducedShortFolder + "\\");
                        this.vsProjectTemplateGeneratorCollection.Add(projectGenerator);
                    }
                    else
                    {
                        if (shortFolder.Equals("_References", StringComparison.InvariantCultureIgnoreCase))
                        {
                            reducedShortFolder = "_Ref";
                        }
                        // Stocke les répertoires physiques des references
                        //if (item.Replace(SourceFolder, "").StartsWith("_References", StringComparison.InvariantCultureIgnoreCase))
                        if (item.Replace(SourceFolder, "").Contains("_References"))
                            {
                            var refElement = new XElement("Reference");
                            refElement.SetAttributeValue("SolutionFolder", shortFolder);
                            refElement.SetAttributeValue("PhysicalFolder", reducedShortFolder);
                            this.referencePathsDocument.Root.Add(refElement);
                        }

                        // Créer le répertoire Output
                        Directory.CreateDirectory(outputFolder + reducedShortFolder);

                        // Créer l'element XML dans le VsTemplate
                        var newElement = this.vsTemplateHelper.CreateSolutionFolderElement(shortFolder);
                        currentElement.Add(newElement);

                        // Parse son contenu
                        this.Parse(newElement, item, outputFolder + reducedShortFolder + "\\");
                    }
                }
                else
                {
                    // Nothing
                }
            }
        }

        private void ParseReferences()
        {
            foreach (var projetTemplate in this.vsProjectTemplateGeneratorCollection)
            {
                bool isUpdated = false;
                var document = this.vsTemplateHelper.ReadDocument(projetTemplate.OutputProjectFile);
                // Recherche des références
                foreach (var itemGroup in document.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "ItemGroup"))
                {
                    foreach (var reference in itemGroup.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "ProjectReference"))
                    {
                        isUpdated = true;
                        var referencedProjectId = this.vsProjectTemplateGeneratorCollection.FirstOrDefault(e => e.ProjectName.Equals(reference.Element(VSTemplateHelper.MSBUILD_NAMESPACE + "Name").Value, StringComparison.InvariantCultureIgnoreCase)).ProjectId;
                        reference.Attribute("Include").Value = reference.Attribute("Include").Value.Replace(TextReplaceHelper.ORIGINAL_NAMESPACE, TextReplaceHelper.COMPANY_NAME + "." + TextReplaceHelper.PROJECT_SHORT_NAME);
                        reference.Element(VSTemplateHelper.MSBUILD_NAMESPACE + "Project").Value = "{" + string.Format(TextReplaceHelper.GUID, referencedProjectId) + "}";
                        reference.Element(VSTemplateHelper.MSBUILD_NAMESPACE + "Name").Value = reference.Element(VSTemplateHelper.MSBUILD_NAMESPACE + "Name").Value.Replace(TextReplaceHelper.ORIGINAL_NAMESPACE, TextReplaceHelper.COMPANY_NAME + "." + TextReplaceHelper.PROJECT_SHORT_NAME);
                    }
                }

                foreach (var propertyGroup in document.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup")) {
                    foreach (var reference in propertyGroup.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "CodeAnalysisLogFile")) {
                        isUpdated = true;

                        reference.Value = reference.Value.Replace(TextReplaceHelper.ORIGINAL_NAMESPACE, TextReplaceHelper.COMPANY_NAME + "." + TextReplaceHelper.PROJECT_SHORT_NAME);
                    }
                }

                if (isUpdated)
                {
                    document.Save(projetTemplate.OutputProjectFile);
                }
            }
        }

        private void ParseWebSiteReference()
         {
            var silverlightGenerator = this.vsProjectTemplateGeneratorCollection.FirstOrDefault(e => this.fileHelper.CheckFilenameSilverlightCore(e.ProjectFilename));
            var webSiteGenerator = this.vsProjectTemplateGeneratorCollection.FirstOrDefault(e => this.fileHelper.CheckFilenameWebSite(e.ProjectFilename));
            if (silverlightGenerator != null && webSiteGenerator != null)
            {
                var document = this.vsTemplateHelper.ReadDocument(webSiteGenerator.OutputProjectFile);
                var element = document.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "SilverlightApplicationList").FirstOrDefault();
                element.Value = ""; // TODO Xap supprimé ! element.Value.Replace(silverlightGenerator.ProjectGuid, "{" + String.Format("$guid{0}$", silverlightGenerator.ProjectId) + "}");

                // // TODO Xap supprimé ! Suppression du Xap dans le fihcier csproj
                var itemGroup = document.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "ItemGroup");
                XElement xapElement = null;
                foreach (var group in itemGroup)
	            {
                    var contentElements = group.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "Content");
                    foreach (var item in contentElements)
                    {
                        if (item.Attribute("Include") != null && item.Attribute("Include").Value.Equals("ClientBin\\Silverlight.Core.xap",StringComparison.InvariantCultureIgnoreCase))
                        {
                            xapElement = item;
                            break;
                        }                     
                    }
                    if (xapElement!=null)
                    {
                        xapElement.Remove();
                        break;
                    }
	            }              

                document.Save(webSiteGenerator.OutputProjectFile);
            }
        }

    }
}
